from fastapi import APIRouter, Depends, HTTPException, status, Query, UploadFile, File
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import desc, asc
from typing import List, Optional
from datetime import datetime
import httpx
import os
import uuid
import re
import asyncio

from database import get_db
from models.user import User
from models.post import Post
from models.category import Category
from models.tag import Tag
from schemas.post import PostCreate, PostUpdate, PostResponse, PostList
from schemas.tag import TagCreate, TagUpdate, TagResponse
from schemas.category import CategoryResponse, CategoryCreate
from routers.auth import get_current_user

router = APIRouter()

# 从环境变量获取服务器主机地址，默认为localhost:8000
SERVER_HOST = os.getenv("SERVER_HOST", "http://localhost:8000")
# 从环境变量获取上传路径，默认为blog/uploads/images
UPLOAD_PATH = os.getenv("UPLOAD_PATH", "blog/uploads/images")


async def download_and_save_image(url: str) -> str:
    """下载外部图片并保存到服务器，返回新的URL"""
    try:
        # 验证URL
        if not url.startswith(('http://', 'https://')):
            return url
        
        # 下载图片
        async with httpx.AsyncClient(timeout=60.0) as client:
            response = await client.get(url)
            response.raise_for_status()
            
            # 检查内容类型
            content_type = response.headers.get('content-type', '')
            if not content_type.startswith('image/'):
                return url
            
            # 生成文件名
            file_extension = content_type.split('/')[-1]
            if file_extension not in ['jpeg', 'jpg', 'png', 'gif', 'webp']:
                file_extension = 'jpg'
            
            filename = f"{uuid.uuid4().hex}.{file_extension}"
            
            # 确保上传目录存在
            upload_dir = UPLOAD_PATH
            os.makedirs(upload_dir, exist_ok=True)
            
            # 保存图片
            file_path = os.path.join(upload_dir, filename)
            with open(file_path, 'wb') as f:
                f.write(response.content)
            
            # 返回完整的服务器URL
            return f"{SERVER_HOST}/{UPLOAD_PATH}/{filename}"
            
    except Exception as e:
        print(f"下载图片失败: {url}, 错误: {e}")
        return url  # 失败时返回原始URL


async def process_content_images(content: str) -> str:
    """处理文章内容中的外部图片，下载并替换为本地URL"""
    if not content:
        return content
    
    # 查找所有外部图片URL
    img_pattern = r'!\[([^\]]*)\]\(([^)]+)\)'
    matches = re.findall(img_pattern, content)
    
    if not matches:
        return content
    
    # 并行下载所有图片
    tasks = []
    for alt_text, url in matches:
        if url.startswith(('http://', 'https://')):
            tasks.append(download_and_save_image(url))
        else:
            tasks.append(asyncio.create_task(asyncio.coroutine(lambda: url)()))
    
    # 等待所有下载完成
    new_urls = await asyncio.gather(*tasks, return_exceptions=True)
    
    # 替换内容中的URL
    for i, (alt_text, original_url) in enumerate(matches):
        if i < len(new_urls) and not isinstance(new_urls[i], Exception):
            new_url = new_urls[i]
            content = content.replace(f"![{alt_text}]({original_url})", f"![{alt_text}]({new_url})")
    
    return content

async def get_final_picsum_url():
    """获取picsum.photos重定向后的真实图片URL"""
    try:
        async with httpx.AsyncClient(timeout=60.0) as client:
            # 使用一个随机数来获取不同的图片，但我们只关心重定向后的最终URL
            response = await client.get("https://picsum.photos/800/400", follow_redirects=True)
            response.raise_for_status()  # 如果请求失败，抛出异常
            return str(response.url)  # 返回最终的URL
    except Exception as e:
        # 如果获取失败，返回一个默认的占位图
        print(f"获取picsum.photos图片失败: {e}")
        return "https://dummyimage.com/800x400/4f46e5/ffffff&text=Error"

@router.get("/list", response_model=List[PostList])
async def get_posts(
    skip: int = Query(0, ge=0),
    limit: int = Query(10, ge=1, le=100),
    published_only: bool = Query(True),
    category_id: Optional[int] = Query(None),
    tag_id: Optional[int] = Query(None),
    search: Optional[str] = Query(None),
    sort_by: str = Query("latest"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """获取文章列表"""
    query = db.query(Post)
    
    if published_only:
        # 只返回已发布的文章
        query = query.filter(Post.is_published == True)
    else:
        # 如果获取草稿，只返回当前用户的草稿（未发布的）
        query = query.filter(Post.author_id == current_user.id, Post.is_published == False)
    
    if category_id:
        query = query.filter(Post.category_id == category_id)
    
    if tag_id:
        query = query.join(Post.tags).filter(Tag.id == tag_id)
    
    if search:
        query = query.filter(
            Post.title.contains(search) | Post.content.contains(search)
        )
    
    # 排序逻辑
    if sort_by == "latest":
        order_by = desc(Post.created_at)
    elif sort_by == "views":
        order_by = desc(Post.view_count)
    elif sort_by == "likes":
        order_by = desc(Post.like_count)
    else:
        order_by = desc(Post.created_at)
    
    posts = query.options(
        joinedload(Post.author),
        joinedload(Post.category),
        joinedload(Post.tags)
    ).order_by(order_by).offset(skip).limit(limit).all()
    return posts

@router.get("/my-posts", response_model=List[PostList])
async def get_my_posts(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """获取当前用户的文章列表"""
    posts = db.query(Post).filter(
        Post.author_id == current_user.id
    ).options(
        joinedload(Post.author),
        joinedload(Post.category),
        joinedload(Post.tags)
    ).order_by(desc(Post.created_at)).all()
    return posts

@router.get("/categories", response_model=List[CategoryResponse])
async def get_all_categories(db: Session = Depends(get_db)):
    """获取所有分类"""
    categories = db.query(Category).all()
    return categories

@router.post("/categories", response_model=CategoryResponse)
async def create_category(
    category: CategoryCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """创建新分类"""
    # 检查分类是否已存在
    existing_category = db.query(Category).filter(Category.name == category.name).first()
    if existing_category:
        return existing_category
    
    # 创建新分类
    db_category = Category(
        name=category.name,
        description=category.description
    )
    
    db.add(db_category)
    db.commit()
    db.refresh(db_category)
    
    return db_category

@router.get("/tags", response_model=List[TagResponse])
async def get_all_tags(db: Session = Depends(get_db)):
    """获取所有标签"""
    tags = db.query(Tag).all()
    return tags

@router.post("/tags", response_model=TagResponse)
async def create_tag(
    tag: TagCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """创建新标签"""
    # 检查标签是否已存在
    existing_tag = db.query(Tag).filter(Tag.name == tag.name).first()
    if existing_tag:
        return existing_tag
    
    # 创建新标签
    db_tag = Tag(
        name=tag.name,
        description=tag.description,
        color=tag.color
    )
    
    db.add(db_tag)
    db.commit()
    db.refresh(db_tag)
    
    return db_tag

@router.put("/tags/{tag_id}", response_model=TagResponse)
async def update_tag(
    tag_id: int,
    tag: TagUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """更新标签"""
    db_tag = db.query(Tag).filter(Tag.id == tag_id).first()
    if not db_tag:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="标签不存在"
        )
    
    # 更新字段
    update_data = tag.dict(exclude_unset=True)
    for field, value in update_data.items():
        setattr(db_tag, field, value)
    
    db.commit()
    db.refresh(db_tag)
    
    return db_tag

@router.delete("/tags/{tag_id}")
async def delete_tag(
    tag_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """删除标签"""
    db_tag = db.query(Tag).filter(Tag.id == tag_id).first()
    if not db_tag:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="标签不存在"
        )
    
    db.delete(db_tag)
    db.commit()
    return {"message": "标签删除成功"}

@router.post("/generate-content")
async def generate_content(
    content: dict,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """自动生成摘要和封面"""
    title = content.get('title', '')
    text_content = content.get('content', '')
    
    # 生成摘要（取前200个字符，清理格式）
    import re
    # 移除Markdown格式符号
    clean_content = re.sub(r'[#*`\-]', '', text_content)
    # 移除多余的空白字符和换行
    clean_content = re.sub(r'\s+', ' ', clean_content).strip()
    # 取前200个字符
    excerpt = clean_content[:200]
    if len(clean_content) > 200:
        excerpt += '...'
    
    # 生成封面图片URL（通过访问picsum.photos获取真实URL）
    cover_image = await get_final_picsum_url()
    
    return {
        "excerpt": excerpt,
        "cover_image": cover_image
    }

@router.get("/{post_id}", response_model=PostResponse)
async def get_post(post_id: str, db: Session = Depends(get_db)):
    """获取单篇文章"""
    post = db.query(Post).filter(Post.id == post_id).first()
    if not post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文章不存在"
        )
    
    # 增加浏览量
    post.view_count += 1
    db.commit()
    
    return post


@router.post("/create", response_model=PostResponse)
async def create_post(
    post: PostCreate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """创建文章"""
    # 简单处理：直接使用传入的内容和封面图片
    processed_content = post.content
    cover_image = post.cover_image
    
    # 如果没有摘要，自动生成
    excerpt = post.excerpt
    if not excerpt:
        # 生成摘要（取前200个字符，清理格式）
        import re
        # 移除Markdown格式符号
        clean_content = re.sub(r'[#*`\-]', '', processed_content)
        # 移除多余的空白字符和换行
        clean_content = re.sub(r'\s+', ' ', clean_content).strip()
        # 取前200个字符
        excerpt = clean_content[:200]
        if len(clean_content) > 200:
            excerpt += '...'
    
    # 创建文章
    db_post = Post(
        title=post.title,
        content=processed_content,
        excerpt=excerpt,
        cover_image=cover_image,
        is_published=post.is_published,
        is_featured=post.is_featured,
        author_id=current_user.id,
        category_id=post.category_id,
        published_at=datetime.utcnow() if post.is_published else None
    )
    
    # 处理标签
    if post.tag_ids:
        tags = db.query(Tag).filter(Tag.id.in_(post.tag_ids)).all()
        db_post.tags.extend(tags)
    
    db.add(db_post)
    db.commit()
    db.refresh(db_post)
    
    return db_post

@router.put("/{post_id}", response_model=PostResponse)
async def update_post(
    post_id: str,
    post: PostUpdate,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """更新文章"""
    db_post = db.query(Post).filter(Post.id == post_id).first()
    if not db_post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文章不存在"
        )
    
    # 检查权限（只有作者或管理员可以编辑）
    if db_post.author_id != current_user.id and not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限编辑此文章"
        )
    
    # 更新字段
    update_data = post.dict(exclude_unset=True)
    print(f"更新文章 {post_id} - 接收到的数据: {update_data}")
    print(f"更新文章 {post_id} - 当前封面图片: {db_post.cover_image}")
    print(f"更新文章 {post_id} - 传入封面图片: {update_data.get('cover_image', '未提供')}")
    
    # 封面图片保护逻辑：如果文章已有封面图片，不更新；否则使用传入的封面图片
    if "cover_image" in update_data:
        if db_post.cover_image and db_post.cover_image.strip():
            # 文章已有封面图片，不更新
            print(f"文章已有封面图片，跳过更新: {db_post.cover_image}")
            update_data.pop("cover_image")
        else:
            # 文章没有封面图片，使用传入的封面图片
            print(f"文章没有封面图片，使用传入的封面图片: {update_data['cover_image']}")
    
    for field, value in update_data.items():
        if field == "tag_ids":
            if value is not None:
                tags = db.query(Tag).filter(Tag.id.in_(value)).all()
                db_post.tags = tags
        else:
            setattr(db_post, field, value)
            print(f"设置字段 {field} = {value}")
    
    print(f"更新后文章封面图片: {db_post.cover_image}")
    
    
    # 如果发布状态改变，更新发布时间
    if "is_published" in update_data and post.is_published and not db_post.published_at:
        db_post.published_at = datetime.utcnow()
    
    db.commit()
    db.refresh(db_post)
    return db_post

@router.delete("/{post_id}")
async def delete_post(
    post_id: str,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """删除文章"""
    db_post = db.query(Post).filter(Post.id == post_id).first()
    if not db_post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文章不存在"
        )
    
    # 检查权限
    if db_post.author_id != current_user.id and not current_user.is_admin:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限删除此文章"
        )
    
    # 删除关联的评论
    from models import Comment
    comments = db.query(Comment).filter(Comment.post_id == post_id).all()
    for comment in comments:
        db.delete(comment)
    
    # 删除文章
    db.delete(db_post)
    db.commit()
    return {"message": "文章删除成功"}


@router.post("/{post_id}/like")
async def like_post(
    post_id: str,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """点赞文章"""
    db_post = db.query(Post).filter(Post.id == post_id).first()
    if not db_post:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文章不存在"
        )
    
    # 增加点赞数
    db_post.like_count += 1
    db.commit()
    db.refresh(db_post)
    
    return {"message": "点赞成功", "like_count": db_post.like_count}


@router.post("/upload-image")
async def upload_image(
    file: UploadFile = File(...),
    current_user: User = Depends(get_current_user)
):
    """上传图片到服务器"""
    # 检查文件类型
    if not file.content_type.startswith('image/'):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="只支持图片文件"
        )
    
    # 检查文件大小（限制为5MB）
    file_size = 0
    content = await file.read()
    file_size = len(content)
    if file_size > 5 * 1024 * 1024:  # 5MB
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="图片文件大小不能超过5MB"
        )
    
    # 创建上传目录
    upload_dir = UPLOAD_PATH
    os.makedirs(upload_dir, exist_ok=True)
    
    # 生成唯一文件名
    file_extension = os.path.splitext(file.filename)[1] if file.filename else '.jpg'
    unique_filename = f"{uuid.uuid4()}{file_extension}"
    file_path = os.path.join(upload_dir, unique_filename)
    
    # 保存文件
    with open(file_path, "wb") as buffer:
        buffer.write(content)
    
    # 返回图片URL（使用完整URL）
    image_url = f"{SERVER_HOST}/{UPLOAD_PATH}/{unique_filename}"
    return {"url": image_url, "filename": unique_filename}


@router.post("/generate-cover-image")
async def generate_cover_image(
    current_user: User = Depends(get_current_user)
):
    """生成封面图片URL"""
    try:
        # 获取外部图片URL
        external_url = await get_final_picsum_url()
        
        # 下载并保存到服务器
        local_url = await download_and_save_image(external_url)
        
        return {"url": local_url, "external_url": external_url}
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"生成封面图片失败: {str(e)}")


@router.post("/migrate-images")
async def migrate_existing_images(
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """批量迁移现有文章的外部图片到服务器"""
    if not current_user.is_admin:
        raise HTTPException(status_code=403, detail="只有管理员可以执行此操作")
    
    # 获取所有有外部图片的文章
    posts = db.query(Post).filter(
        Post.cover_image.like('http%')
    ).all()
    
    updated_count = 0
    
    for post in posts:
        try:
            # 处理封面图片
            if post.cover_image and post.cover_image.startswith(('http://', 'https://')):
                new_cover_image = await download_and_save_image(post.cover_image)
                if new_cover_image != post.cover_image:
                    post.cover_image = new_cover_image
                    updated_count += 1
            
            # 处理文章内容中的图片
            if post.content:
                processed_content = await process_content_images(post.content)
                if processed_content != post.content:
                    post.content = processed_content
                    updated_count += 1
            
        except Exception as e:
            print(f"处理文章 {post.id} 失败: {e}")
            continue
    
    # 提交所有更改
    db.commit()
    
    return {
        "message": f"成功处理 {len(posts)} 篇文章，更新了 {updated_count} 个图片",
        "processed_posts": len(posts),
        "updated_images": updated_count
    }


